package czt.ocr.util.httpclient;

import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Map;



@Component
public class HttpClient {

    /**
              * 默认字符集
     */
    public static final String DEFAULT_CHARSET = "UTF-8";

    @Autowired
    private CloseableHttpClient closeableHttpClient;

    @Autowired
    private RequestConfig requestConfig;


    /**
     * 用于JSON格式的API调用
     *
     * @param url              url地址
     * @param requestParameter 请求参数
     * @param clazz            接口返回值的类型
     * @return
     * @throws Exception
     */
    public <T> T doGet(String url, Map<String, Object> requestParameter, Class<T> clazz) throws Exception {
        String responseJson = this.doGet(url, requestParameter);
        T response = JSONObject.parseObject(responseJson, clazz);
        return response;
    }

    public String doGet(String url, Map<String, Object> requestParameter) throws Exception {
        URIBuilder uriBuilder = new URIBuilder(url);

        if (requestParameter != null) {
            for (Map.Entry<String, Object> entry : requestParameter.entrySet()) {
                uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
            }
        }

        return this.doGet(uriBuilder.build().toString());
    }

    public String doGet(String url) throws Exception {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);
        httpGet.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
        CloseableHttpResponse response = this.closeableHttpClient.execute(httpGet);

        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            throw new Exception("api request exception, http reponse code:" + statusCode);
        }

        return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    }


    public String doGetHeader(String url, Map<String, String> headerParameter) throws Exception {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);
        if (!headerParameter.isEmpty()){
            for (String key : headerParameter.keySet()) {
                httpGet.addHeader(key,headerParameter.get(key));
            }
        }
        httpGet.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
        CloseableHttpResponse response = this.closeableHttpClient.execute(httpGet);

        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            throw new Exception("api request exception, http reponse code:" + statusCode);
        }

        return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    }

    public <T> T doPost(String url, Map<String, Object> requestParameter, Class<T> clazz) throws Exception {
        HttpResponse httpResponse = this.doPost(url, requestParameter);
        int statusCode = httpResponse.getCode();
        if (statusCode != HttpStatus.SC_OK) {
            throw new Exception("api request exception, http reponse code:" + statusCode);
        }

        T response = JSONObject.parseObject(httpResponse.getBody(), clazz);
        return response;
    }

    public HttpResponse doPost(String url, Map<String, Object> requestParameter) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());

        if (requestParameter != null) {
            String requestBody = JSONObject.toJSONString(requestParameter);
            StringEntity postEntity = new StringEntity(requestBody, "UTF-8");
            httpPost.setEntity(postEntity);
        }
        CloseableHttpResponse response = this.closeableHttpClient.execute(httpPost);
        // 对请求的响应进行简单的包装成自定义的类型
        return new HttpResponse(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                response.getEntity(), DEFAULT_CHARSET));
    }

    public HttpResponse doPost(String url, Map<String, Object> requestParameter,Map<String, Object> headerParameter) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
        if (!headerParameter.isEmpty()){
            for (String key : headerParameter.keySet()) {
                httpPost.addHeader(key,headerParameter.get(key).toString());
            }
        }

        if (requestParameter != null) {
            String requestBody = JSONObject.toJSONString(requestParameter);
            StringEntity postEntity = new StringEntity(requestBody, "UTF-8");
            httpPost.setEntity(postEntity);
        }

        CloseableHttpResponse response = this.closeableHttpClient.execute(httpPost);
        // 对请求的响应进行简单的包装成自定义的类型
        return new HttpResponse(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                response.getEntity(), DEFAULT_CHARSET));
    }

    public HttpResponse doHttpsDelete(String url, Map<String, Object> headerParameter) throws Exception {
        // 创建绕过 SSL 验证的 HttpClient 实例
        SSLConnectionSocketFactory sslsf = createIgnoreVerifySSL();
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();

        HttpDelete httpDelete = new HttpDelete(url);
        httpDelete.setConfig(requestConfig);

        // 添加头信息
        for (Map.Entry<String, Object> entry : headerParameter.entrySet()) {
            httpDelete.addHeader(entry.getKey(), entry.getValue().toString());
        }

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpDelete);
            // 对请求的响应进行简单的包装成自定义的类型
            return new HttpResponse(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                    response.getEntity(), DEFAULT_CHARSET));
        } finally {
            // 确保响应体被关闭
            if (response != null) {
                response.close();
            }
            // 确保HttpClient被关闭
            httpClient.close();
        }
    }
    public <T> HttpResponse doHttpsPost(String url, T requestParameter, Map<String, Object> headerParameter) throws Exception {
        // 创建绕过 SSL 验证的 HttpClient 实例
        SSLConnectionSocketFactory sslsf = createIgnoreVerifySSL();
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();

        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);

        // 添加头信息
        for (Map.Entry<String, Object> entry : headerParameter.entrySet()) {
            httpPost.addHeader(entry.getKey(), entry.getValue().toString());
        }

        if (requestParameter != null) {
            String requestBody = JSONObject.toJSONString(requestParameter);
            StringEntity postEntity = new StringEntity(requestBody, "UTF-8");
            httpPost.setEntity(postEntity);
        }

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);
            // 对请求的响应进行简单的包装成自定义的类型
            return new HttpResponse(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                    response.getEntity(), DEFAULT_CHARSET));
        } finally {
            // 确保响应体被关闭
            if (response != null) {
                response.close();
            }
            // 确保HttpClient被关闭
            httpClient.close();
        }
    }

    /**
     * 绕过验证
     *
     * @return {@link SSLConnectionSocketFactory}
     * @throws NoSuchAlgorithmException no such algorithm exception
     * @throws KeyManagementException   key management exception
     */
    public static SSLConnectionSocketFactory createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLConnectionSocketFactory sslsf = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");

            // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public void checkClientTrusted(
                        java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                        String paramString) throws CertificateException {
                }
                @Override
                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                        String paramString) throws CertificateException {
                }
                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            sc.init(null, new TrustManager[] { trustManager }, null);
            sslsf = new SSLConnectionSocketFactory(sc, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        }catch (GeneralSecurityException e){
            e.printStackTrace();
        }
        return sslsf;
    }
    public HttpResponse doPost(String url, List<?> requestParameter) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());

        if (requestParameter != null) {
            String requestBody = JSONObject.toJSONString(requestParameter);
            StringEntity postEntity = new StringEntity(requestBody, "UTF-8");
            httpPost.setEntity(postEntity);
        }
        CloseableHttpResponse response = this.closeableHttpClient.execute(httpPost);
        // 对请求的响应进行简单的包装成自定义的类型
        return new HttpResponse(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                response.getEntity(), DEFAULT_CHARSET));
    }

    public HttpResponse doPost(String url, List<?> requestParameter,Map<String, String> headerParameter) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
        if (!headerParameter.isEmpty()){
            for (String key : headerParameter.keySet()) {
                httpPost.addHeader(key,headerParameter.get(key));
            }
        }

        if (requestParameter != null) {
            String requestBody = JSONObject.toJSONString(requestParameter);
            StringEntity postEntity = new StringEntity(requestBody, "UTF-8");
            httpPost.setEntity(postEntity);
        }

        CloseableHttpResponse response = this.closeableHttpClient.execute(httpPost);
        // 对请求的响应进行简单的包装成自定义的类型
        return new HttpResponse(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                response.getEntity(), DEFAULT_CHARSET));
    }

    public HttpResponse doPost(String url, String requestParameter,Map<String, String> headerParameter) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
        if (!headerParameter.isEmpty()){
            for (String key : headerParameter.keySet()) {
                httpPost.addHeader(key,headerParameter.get(key));
            }
        }

        if (StringUtils.isNotBlank(requestParameter)) {
            StringEntity postEntity = new StringEntity(requestParameter, "UTF-8");
            httpPost.setEntity(postEntity);
        }

        CloseableHttpResponse response = this.closeableHttpClient.execute(httpPost);
        // 对请求的响应进行简单的包装成自定义的类型
        return new HttpResponse(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                response.getEntity(), DEFAULT_CHARSET));
    }

    public HttpResponse doPost(String url,byte[] body, Map<String, String> headerParameter) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
        if (!headerParameter.isEmpty()){
            for (String key : headerParameter.keySet()) {
                httpPost.addHeader(key,headerParameter.get(key));
            }
        }

        if (body != null) {
            ByteArrayEntity postEntity = new ByteArrayEntity(body);
            httpPost.setEntity(postEntity);
        }
        CloseableHttpResponse response = this.closeableHttpClient.execute(httpPost);
        OutputStream out = new ByteArrayOutputStream();
        response.getEntity().writeTo(out);
        ;
        // 对请求的响应进行简单的包装成自定义的类型
        return new HttpResponse(response.getStatusLine().getStatusCode(), ((ByteArrayOutputStream) out).toByteArray());
    }

    /**
     * 封住请求的响应码和响应的内容
     */
    public class HttpResponse {
        /**
         * http status
         */
        private Integer code;
        /**
         * http response content
         */
        private String body;

        private byte[] bodyByte;

        public byte[] getBodyByte() {
            return bodyByte;
        }

        public void setBodyByte(byte[] bodyByte) {
            this.bodyByte = bodyByte;
        }

        public HttpResponse() {
        }

        public HttpResponse(Integer code, String body) {
            this.code = code;
            this.body = body;
        }

        public HttpResponse(int code, byte[] bodyByte) {
            this.code = code;
            this.bodyByte=bodyByte;
        }

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getBody() {
            return body;
        }

        public void setBody(String body) {
            this.body = body;
        }
    }
}
